* For example, consider a packet that holds onto resources belonging to the
* guest for which it is queued (e.g., packet received on vif1.0, destined for
* vif1.1 which is not activated in the guest): in this situation the guest
- * will never be destroyed, unless vif1.1 is taken down (which flushes the
- * 'tx_queue').
- *
- * Only set this parameter to non-zero value if you know what you are doing!
+ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
+ * run a timer (tx_queue_timeout) to drain the queue when the interface is
+ * blocked.
*/
-static unsigned long netbk_queue_length = 0;
+static unsigned long netbk_queue_length = 32;
module_param_named(queue_length, netbk_queue_length, ulong, 0);
static void __netif_up(netif_t *netif)
{
disable_irq(netif->irq);
netif_deschedule_work(netif);
- del_timer_sync(&netif->credit_timeout);
}
static int net_open(struct net_device *dev)
netif->credit_bytes = netif->remaining_credit = ~0UL;
netif->credit_usec = 0UL;
init_timer(&netif->credit_timeout);
+ /* Initialize 'expires' now: it's used to track the credit window. */
netif->credit_timeout.expires = jiffies;
+ init_timer(&netif->tx_queue_timeout);
+
dev->hard_start_xmit = netif_be_start_xmit;
dev->get_stats = netif_be_get_stats;
dev->open = net_open;
return err;
}
-static void netif_free(netif_t *netif)
+void netif_disconnect(netif_t *netif)
{
+ if (netif_carrier_ok(netif->dev)) {
+ rtnl_lock();
+ netif_carrier_off(netif->dev);
+ if (netif_running(netif->dev))
+ __netif_down(netif);
+ rtnl_unlock();
+ netif_put(netif);
+ }
+
atomic_dec(&netif->refcnt);
wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
+ del_timer_sync(&netif->credit_timeout);
+ del_timer_sync(&netif->tx_queue_timeout);
+
if (netif->irq)
unbind_from_irqhandler(netif->irq, netif);
free_netdev(netif->dev);
}
-
-void netif_disconnect(netif_t *netif)
-{
- if (netif_carrier_ok(netif->dev)) {
- rtnl_lock();
- netif_carrier_off(netif->dev);
- if (netif_running(netif->dev))
- __netif_down(netif);
- rtnl_unlock();
- netif_put(netif);
- }
- netif_free(netif);
-}
((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
}
+static void tx_queue_callback(unsigned long data)
+{
+ netif_t *netif = (netif_t *)data;
+ if (netif_schedulable(netif->dev))
+ netif_wake_queue(netif->dev);
+}
+
int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
netif_t *netif = netdev_priv(dev);
BUG_ON(skb->dev != dev);
/* Drop the packet if the target domain has no receive buffers. */
- if (unlikely(!netif_running(dev) || !netif_carrier_ok(dev)))
+ if (unlikely(!netif_schedulable(dev) || netbk_queue_full(netif)))
goto drop;
- if (unlikely(netbk_queue_full(netif))) {
- /* Not a BUG_ON() -- misbehaving netfront can trigger this. */
- if (netbk_can_queue(dev))
- DPRINTK("Queue full but not stopped!\n");
- goto drop;
- }
-
- /* Copy the packet here if it's destined for a flipping
- interface but isn't flippable (e.g. extra references to
- data)
- */
+ /*
+ * Copy the packet here if it's destined for a flipping interface
+ * but isn't flippable (e.g. extra references to data).
+ */
if (!netif->copying_receiver && !is_flippable_skb(skb)) {
struct sk_buff *nskb = netbk_copy_skb(skb);
if ( unlikely(nskb == NULL) )
netif->rx.sring->req_event = netif->rx_req_cons_peek +
netbk_max_required_rx_slots(netif);
mb(); /* request notification /then/ check & stop the queue */
- if (netbk_queue_full(netif))
+ if (netbk_queue_full(netif)) {
netif_stop_queue(dev);
+ /*
+ * Schedule 500ms timeout to restart the queue, thus
+ * ensuring that an inactive queue will be drained.
+ * Packets will be immediately be dropped until more
+ * receive buffers become available (see
+ * netbk_queue_full() check above).
+ */
+ netif->tx_queue_timeout.data = (unsigned long)netif;
+ netif->tx_queue_timeout.function = tx_queue_callback;
+ __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
+ }
}
skb_queue_tail(&rx_queue, skb);
}
if (netif_queue_stopped(netif->dev) &&
+ netif_schedulable(netif->dev) &&
!netbk_queue_full(netif))
netif_wake_queue(netif->dev);
spin_lock_irq(&net_schedule_list_lock);
if (!__on_net_schedule_list(netif) &&
- likely(netif_running(netif->dev) &&
- netif_carrier_ok(netif->dev))) {
+ likely(netif_schedulable(netif->dev))) {
list_add_tail(&netif->list, &net_schedule_list);
netif_get(netif);
}
add_to_net_schedule_list_tail(netif);
maybe_schedule_tx_action();
- if (netif_queue_stopped(netif->dev) && !netbk_queue_full(netif))
+ if (netif_schedulable(netif->dev) && !netbk_queue_full(netif))
netif_wake_queue(netif->dev);
return IRQ_HANDLED;